package com.yootoo.extpmml.dsl

import groovy.util.logging.Slf4j
import okhttp3.OkHttpClient
import org.springframework.scheduling.config.CronTask
import org.springframework.scheduling.config.IntervalTask
import org.springframework.scheduling.config.ScheduledTask
import org.springframework.scheduling.config.ScheduledTaskRegistrar

import javax.net.ssl.KeyManagerFactory
import java.security.KeyStore
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicInteger

@Slf4j
class AdapterExecutor {
    private static threadCount = new AtomicInteger(0)
    private
    static final ScheduledTaskRegistrar scheduler = new ScheduledTaskRegistrar()
    private static Map<String, ScheduledTask> scheduledFutures = new ConcurrentHashMap<>()
    def global = new ConcurrentHashMap()
    Map<String, Closure> api
    Map<String, AdapterRequest> resolvedApi = [:]
    private final AdapterSpec spec
    private final String name
    def httpClient
    def globalContext

    static {
        scheduler.scheduler = Executors.newScheduledThreadPool(4, { r ->
            def t = new Thread(r, "Delegate-Scheduler-${threadCount.getAndIncrement()}")
            t.setDaemon(true)
            t
        })
    }


    AdapterExecutor(AdapterSpec adapterSpec, String name, Map<String, Object> constants) {
        this.name = name
        if (constants) {
            global.putAll(constants)
        }
        cancelScheduledTask(name)
        spec = adapterSpec
        if (spec.givenCall) {
            spec.givenCall.delegate = this
            spec.givenCall()
        }
        def builder = new OkHttpClient.Builder()

        //初始化http连接时间
        builder.connectTimeout(global?.httpConnectionTimeout ?: 10000, TimeUnit.MILLISECONDS)
        builder.writeTimeout(global?.httpReadTimeout ?: 10000, TimeUnit.MILLISECONDS)
        builder.readTimeout(global?.httpWriteTimeout ?: 10000, TimeUnit.MILLISECONDS)

        httpClient = builder.build()
        def delegate = this
        api.each { k, v ->
            def request = new AdapterRequest()
            resolvedApi[k] = v.rehydrate(delegate, delegate, request)()
        }
        globalContext = new AdapterContext(name: name, global: global, api: resolvedApi, client: httpClient)
        // 定时任务的delegate
        if (spec.scheduleCall) {
            spec.scheduleCall.delegate = globalContext
            def task
            def command = {
                while (true) {
                    try {
                        log.info("开始[{}]定时任务.", name)
                        spec.scheduleCall()
                        log.info("执行[{}]定时任务成功.", name)
                        break
                    } catch (Exception e) {
                        log.info("执行[{}]定时任务失败, 1s后重新执行.", name, e)
                        Thread.sleep(1000L)
                    }
                }
            }
            try {
                if (spec.cron) {
                    task = scheduler.scheduleCronTask(new CronTask(command, spec.cron))
                    log.info("设置[{}](cron)定时任务成功.", name)
                } else {
                    task = scheduler.scheduleFixedDelayTask(new IntervalTask(command, spec.rate, 0))
                    log.info("设置[{}](delay)定时任务成功.", name)
                }
                scheduledFutures.put(name, task)
            } catch (Exception e) {
                log.error("设置[{}]定时任务失败.", name, e)
            }
        }
    }

    Object doAdapter(Map<String, Object> bodyFromController) {
        try {
            def context = new AdapterContext(name: name, global: global, input: bodyFromController, api: resolvedApi, client: httpClient)
            def result = spec.executeCall.rehydrate(context, this, spec)()
            if (result) {
                return result
            } else {
                return context.response.body
            }
        } catch (Exception e) {
            throw e
        }
    }

    static void cancelScheduledTask(String name) {
        if (scheduledFutures.remove(name)?.cancel()) {
            log.info("停止[{}]定时任务成功.", name)
        }
    }


    def getClientKeyFactory() {

        String client_passwd = "51nb"
        KeyStore keyStore = KeyStore.getInstance("PKCS12")
        try {
            keyStore.load(AdapterExecutor.class.getResourceAsStream("/publicKey/client-xScore.p12"), client_passwd.toCharArray())
        } catch (Exception e) {
            log.error("Adapter初始化加载证书失败.", e)
        }
        // Initialize KeyStore Factory
        KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509")

        try {
            keyManagerFactory.init(keyStore, client_passwd.toCharArray())
        } catch (Exception e) {
            log.error("Adapter初始化失败.", e)
        }
        return keyManagerFactory
    }
}
